package cn.ronghuanet.auth.interceptor;

import cn.ronghuanet.auth.annotation.RonghuaPermission;
import cn.ronghuanet.auth.mapper.PermissionMapper;
import cn.ronghuanet.basic.util.BasicMap;
import cn.ronghuanet.org.domain.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * 认证授权拦截器
 * 认证(登录)拦截  如果用户没有登录,就不允许访问
 * 权限拦截(鉴权)  如果用户访问的资源没有权限,不允许访问
 */
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1 认证(登录)拦截
        // 1.1 获取前端请求头中传过来的token
        String token = request.getHeader("token");

        // 1.2 判断token是否为空,如果为空说明前端没有做过登录操作,就拦截
        if(StringUtils.isEmpty(token)){
            response.getWriter().write("{\"success\":false,\"message\":\"noLogin\"}");
            return false;
        }

        // 1.3 根据token去loginMap中获取登录用户信息
        Object loginUser = BasicMap.loginMap.get(token);

        // 1.4 判断登录用户信息是否为空,不为空就说明登录过,就放行,否则就拦截
        if(Objects.isNull(loginUser)){
            response.getWriter().write("{\"success\":false,\"message\":\"noLogin\"}");
            return false;
        }
        // 强转为Employee类型
        Employee employee = (Employee)loginUser;

        // 2 权限拦截
        if(handler instanceof HandlerMethod){
            HandlerMethod handlerMethod = (HandlerMethod)handler;
            Method method = handlerMethod.getMethod();  // java反射中的Method对象
            // 2.1 判断用户要访问的资源(url)需不需要权限,如果该资源不需要权限,就直接放行 比如说:首页就不需要权限,每个员工都能访问
            // 判断当前这个资源要访问的controller的方法上面有没有@RonghuaPermission注解
            RonghuaPermission annotation = method.getAnnotation(RonghuaPermission.class);
            if(Objects.isNull(annotation)){
                // 为空说明当前方法不需要权限
                return true;
            }
            // 2.2 如果资源需要权限,判断用户他有没有当前要访问的这个资源的权限
            // 2.2.1 首先要拿到这个用户它所拥有的所有权限(通过角色)
            List<String> permissionSns = permissionMapper.getPermissioNSnsByEmployeeId(employee.getId());

            // 2.2.2 要获取当前这个资源的权限   /employee/list 它的权限是什么?   类名:方法名
            Class<?> aClass = method.getDeclaringClass();
            String sn = aClass.getSimpleName()+":"+method.getName();

            // 2.2.3 判断用户拥有的权限里面包不包含这个资源的资源
            if(!permissionSns.contains(sn)){
                // 2.2.3.1 不包含就拦截,并且要返回错误信息
                // 因为前后端分离项目,前端是通过axios发起的异步请求,所以后端只能返回具体的结果,而是不能访问页面的
                // 而我们的每个接口的返回结果都是 {success:,message:""},所以我们在这个地方也就返回这个格式就可以了,如果格式不一样,那么前端它就不好处理
                // 当然这个地方也可以用一个map来装,然后转成json格式字符串,或者是用AjaxResult对象,也要转成json格式的字符串
                response.getWriter().write("{\"success\":false,\"message\":\"noPermission\"}");
                return false;
            }
        }
        // 放行
        return true;
    }

}
